package com.dd.cloud.user.service.file.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dd.cloud.common.config.obs.FileUrlPrefix;
import com.dd.cloud.common.constants.FileConstants;
import com.dd.cloud.common.constants.HealthConstants;
import com.dd.cloud.common.enums.ZkExceptionEnum;
import com.dd.cloud.common.exception.ZekeException;
import com.dd.cloud.common.interceptor.UserInterceptor;
import com.dd.cloud.common.utils.ObjectUtils;
import com.dd.cloud.common.utils.ResourceDownloadUtil;
import com.dd.cloud.common.utils.UploadUtil;
import com.dd.cloud.common.vo.LoginInfo;
import com.dd.cloud.user.entity.file.FileInfo;
import com.dd.cloud.user.mapper.file.FileInfoMapper;
import com.dd.cloud.user.req.file.FilePageReq;
import com.dd.cloud.user.res.file.FileUploadProgressRes;
import com.dd.cloud.user.service.file.IFileInfoService;
import com.dd.cloud.user.util.HuaWeiOBSUtil;
import com.github.tobato.fastdfs.service.FastFileStorageClient;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.File;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

/**
 * <p>
 * 文件表 服务实现类
 * </p>
 *
 * @author czg
 * @since 2022-03-23
 */
@Service
@Slf4j
public class FileInfoServiceImpl extends ServiceImpl<FileInfoMapper, FileInfo> implements IFileInfoService {
    @Autowired
    public FastFileStorageClient storageClient;
    @Autowired
    private FileUrlPrefix prefix;
    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    /**
     * 下载模板文件
     *
     * @param client
     * @param response
     */
    @Override
    public void downloadTemplate(String client, HttpServletResponse response) {
        String fileName = "template/批量导入医生模版.xlsx";
        if (!StringUtils.isBlank(client) && client.equals(HealthConstants.ClientType.HEALTHMECHAN)) {
            fileName = "template/名老中医智能辅助诊疗（学习）机构添加医生信息表.xlsx";
        }
        ResourceDownloadUtil.resourceDownload(response, fileName);
    }

    /**
     * 单文件上传
     *
     * @param file
     * @return
     */
    @Override
    public FileInfo uploadSingleFile(MultipartFile file) {
        String url = HuaWeiOBSUtil.uploadFiles(file);
        LoginInfo loginInfo = UserInterceptor.getLoginUserInfo().get();
        FileInfo fileInfo = new FileInfo();
        fileInfo.setFileName(file.getName());
        fileInfo.setFileOriginalName(file.getOriginalFilename());
        //文件大小, 字节数 转成KB需/1024
        fileInfo.setFileSize(file.getSize());
        fileInfo.setFileUrl(url);
        if (loginInfo != null) {
            fileInfo.setFounderId(loginInfo.getId());
            fileInfo.setFounderType(loginInfo.getType());
            fileInfo.setFounderName(loginInfo.getName());
        }
        fileInfo.setCreateDate(LocalDateTime.now());
        fileInfo.setContentType(file.getContentType());
        fileInfo.setStatus(FileConstants.FileStatus.NOMAL);
        boolean i = save(fileInfo);
        if (!i) {
            throw new ZekeException(500, "文件保存失败");
        }
        log.info("文件上传:{}", fileInfo);
        //ImageUtils.addImageServer(fileInfo);
        return fileInfo;
    }

    /**
     * 单文件上传
     *
     * @param file
     * @return
     */
    @Override
    public FileInfo uploadSingleFile(File file) {
        String url = HuaWeiOBSUtil.uploadFile(file);
        LoginInfo loginInfo = UserInterceptor.getLoginUserInfo().get();
        FileInfo fileInfo = new FileInfo();
        fileInfo.setFileName(file.getName());
        fileInfo.setFileOriginalName(file.getName());
        //文件大小, 字节数 转成KB需/1024
        fileInfo.setFileSize(file.length());
        fileInfo.setFileUrl(url);
        if (loginInfo != null) {
            fileInfo.setFounderId(loginInfo.getId());
            fileInfo.setFounderType(loginInfo.getType());
            fileInfo.setFounderName(loginInfo.getName());
        }
        fileInfo.setCreateDate(LocalDateTime.now());
        fileInfo.setStatus(FileConstants.FileStatus.NOMAL);
        boolean i = save(fileInfo);
        if (!i) {
            throw new ZekeException(500, "文件保存失败");
        }
        log.info("文件上传:{}", fileInfo);
        //ImageUtils.addImageServer(fileInfo);
        return fileInfo;
    }

    /**
     * 单文件上传, 返回字符串
     *
     * @param file
     * @return
     */
    @Override
    public String uploadSingleFileStr(MultipartFile file) {
        String url = HuaWeiOBSUtil.uploadFiles(file);
        LoginInfo loginInfo = UserInterceptor.getLoginUserInfo().get();
        FileInfo fileInfo = new FileInfo();
        fileInfo.setFileName(file.getName());
        fileInfo.setFileOriginalName(file.getOriginalFilename());
        //文件大小, 字节数 转成KB需/1024
        fileInfo.setFileSize(file.getSize());
        fileInfo.setFileUrl(url);
        if (loginInfo != null) {
            fileInfo.setFounderId(loginInfo.getId());
            fileInfo.setFounderType(loginInfo.getType());
            fileInfo.setFounderName(loginInfo.getName());
        }
        fileInfo.setCreateDate(LocalDateTime.now());
        fileInfo.setContentType(file.getContentType());
        fileInfo.setStatus(FileConstants.FileStatus.NOMAL);
        boolean i = save(fileInfo);
        if (!i) {
            throw new ZekeException(500, "文件保存失败");
        }
        log.info("文件上传:{}", fileInfo);
        return prefix.addImageServer(fileInfo.getFileUrl());
    }

    /**
     * 多文件上传
     *
     * @param files
     * @return
     */
    @Override
    public List<FileInfo> uploadMultipleFile(MultipartFile[] files) {
        LoginInfo loginInfo = UserInterceptor.getLoginUserInfo().get();
        List<FileInfo> list = new ArrayList<>();
        for (int j = 0; j < files.length; j++) {
            MultipartFile file = files[j];
            FileInfo fileInfo = new FileInfo();
            fileInfo.setFileName(file.getName());
            fileInfo.setFileOriginalName(file.getOriginalFilename());
            //文件大小, 字节数 转成KB需/1024
            fileInfo.setFileSize(file.getSize());
            fileInfo.setFileUrl(HuaWeiOBSUtil.uploadFiles(file));
            if (loginInfo != null) {
                fileInfo.setFounderId(loginInfo.getId());
                fileInfo.setFounderType(loginInfo.getType());
                fileInfo.setFounderName(loginInfo.getName());
            }
            fileInfo.setCreateDate(LocalDateTime.now());
            fileInfo.setContentType(file.getContentType());
            fileInfo.setStatus(FileConstants.FileStatus.NOMAL);
            list.add(fileInfo);
        }
        boolean i = saveBatch(list);
        if (!i) {
            throw new ZekeException(500, "文件保存失败");
        }
        log.info("文件批量上传:{}", list);
        for (FileInfo item : list) {
            prefix.addImageServer(item);
        }
        return list;
    }

    /**
     * 多文件上传
     *
     * @param files
     * @return
     */
    @Override
    public List<FileInfo> uploadMultipleFile(File[] files) {
        LoginInfo loginInfo = UserInterceptor.getLoginUserInfo().get();
        List<FileInfo> list = new ArrayList<>();
        for (int j = 0; j < files.length; j++) {
            File file = files[j];
            FileInfo fileInfo = new FileInfo();
            fileInfo.setFileName(file.getName());
            fileInfo.setFileOriginalName(file.getName());
            //文件大小, 字节数 转成KB需/1024
            fileInfo.setFileSize(file.length());
            fileInfo.setFileUrl(HuaWeiOBSUtil.uploadFile(file));
            if (loginInfo != null) {
                fileInfo.setFounderId(loginInfo.getId());
                fileInfo.setFounderType(loginInfo.getType());
                fileInfo.setFounderName(loginInfo.getName());
            }
            fileInfo.setCreateDate(LocalDateTime.now());
            fileInfo.setStatus(FileConstants.FileStatus.NOMAL);
            list.add(fileInfo);
        }
        boolean i = saveBatch(list);
        if (!i) {
            throw new ZekeException(500, "文件保存失败");
        }
        log.info("文件批量上传:{}", list);
        return list;
    }

    /**
     * 单文件上传, 返回字符串
     *
     * @param file
     * @param fix  是否要加文件服务器前缀
     * @return
     */
    @Override
    public String uploadSingleFileStr(MultipartFile file, boolean fix) {

        String url = HuaWeiOBSUtil.uploadFiles(file);
        LoginInfo loginInfo = UserInterceptor.getLoginUserInfo().get();
        FileInfo fileInfo = new FileInfo();
        fileInfo.setFileName(file.getName());
        fileInfo.setFileOriginalName(file.getOriginalFilename());
        //文件大小, 字节数 转成KB需/1024
        fileInfo.setFileSize(file.getSize());
        fileInfo.setFileUrl(url);
        if (loginInfo != null) {
            fileInfo.setFounderId(loginInfo.getId());
            fileInfo.setFounderType(loginInfo.getType());
            fileInfo.setFounderName(loginInfo.getName());
        }
        fileInfo.setCreateDate(LocalDateTime.now());
        fileInfo.setContentType(file.getContentType());
        fileInfo.setStatus(FileConstants.FileStatus.NOMAL);
        boolean i = save(fileInfo);
        if (!i) {
            throw new ZekeException(500, "文件保存失败");
        }
        log.info("文件上传:{}", fileInfo);
        if (fix) {
            return prefix.addImageServer(fileInfo.getFileUrl());
        }
        return fileInfo.getFileUrl();
    }

    /**
     * 文件预览
     *
     * @param response
     * @param fileUrl  文件全路径
     */
    @Override
    public FileInfo preview(HttpServletResponse response, String fileUrl) {
        UploadUtil.preview(fileUrl, response);
        fileUrl = prefix.deleteImageServer(fileUrl);
        QueryWrapper<FileInfo> qw = new QueryWrapper<>();
        qw.lambda().eq(FileInfo::getFileUrl, fileUrl);
        return getOne(qw);
    }

    /**
     * 文件下载
     *
     * @param fileInfo 文件对象
     * @param response
     */
    @Override
    public void downloadFile(FileInfo fileInfo, HttpServletResponse response) {
        prefix.addImageServer(fileInfo);
        try {
            UploadUtil.downloadFile(fileInfo.getFileUrl(), fileInfo.getFileOriginalName(), response);
        } catch (Exception e) {
            e.printStackTrace();
            throw new ZekeException(500, "文件下载失败");
        }
    }

    /**
     * 网络文件下载
     *
     * @param fileInfo 文件路径
     * @param response
     */
    @Override
    public void downloadNetFile(FileInfo fileInfo, HttpServletResponse response) {
        prefix.addImageServer(fileInfo);
        UploadUtil.downloadNetFileToClient(response, fileInfo.getFileUrl(), fileInfo.getFileOriginalName());
    }

    /**
     * 查询文件上传进度
     *
     * @param request
     * @return
     */
    @Override
    public FileUploadProgressRes uploadProgress(HttpServletRequest request, String time) {
        HttpSession session = request.getSession();
        FileUploadProgressRes res = new FileUploadProgressRes();

        return res;
    }

    /**
     * @param req:
     * @return Page<FileInfo>
     * @description 分页查询文件
     * @author czg
     * @date 2023/5/31 10:39
     */
    @Override
    public Page<FileInfo> filePage(FilePageReq req) {
        QueryWrapper<FileInfo> qw = new QueryWrapper<>();
        qw.lambda().eq(FileInfo::getStatus, 1);
        Page<FileInfo> page = req.pagePojo();
        if (!StringUtils.isBlank(req.getKeyword())) {
            qw.lambda().and(t -> t.eq(FileInfo::getFileName, req.getKeyword()).or().eq(FileInfo::getFileOriginalName, req.getKeyword()));
        }
        if (req.getType() != null) {
            qw.lambda().eq(FileInfo::getUseType, req.getType());
        }
        qw.lambda().orderByDesc(FileInfo::getCreateDate);
        page = page(page, qw);
        return page;
    }

    /**
     * @param fileInfo:
     * @return void
     * @description 添加文件
     * @author czg
     * @date 2023/5/31 10:47
     */
    @Override
    public void addFile(FileInfo fileInfo) {
        LoginInfo loginInfo = UserInterceptor.getLoginUserInfo().get();
        fileInfo.setCreateDate(LocalDateTime.now());
        fileInfo.setFounderId(loginInfo.getId());
        fileInfo.setFounderType(loginInfo.getType());
        fileInfo.setStatus(1);
        boolean save = save(fileInfo);
        if (!save) {
            throw new ZekeException("保存失败");
        }
    }

    /**
     * @param id:     文件id
     * @param status: 文件状态
     * @return void
     * @description 修改文件状态
     * @author czg
     * @date 2023/5/31 11:22
     */
    @Override
    public void updateFileStatus(Integer id, Integer status) {
        FileInfo byId = getById(id);
        if (byId == null) {
            throw new ZekeException("文件不存在");
        }
        if (byId.getStatus().equals(status)) {
            return;
        }
        if (!ObjectUtils.refrect(FileConstants.FileStatus.class, status)) {
            throw new ZekeException(ZkExceptionEnum.STATUS_DATA_ERROR);
        }
        byId.setStatus(status);
        boolean b = updateById(byId);
        if (!b) {
            throw new ZekeException(ZkExceptionEnum.UPDATE_ERROR);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<FileInfo> getFileStr(MultipartFile[] files) {
        List<FileInfo> list = new ArrayList<>();
        for (int j = 0; j < files.length; j++) {
            MultipartFile file = files[j];
            FileInfo fileInfo = new FileInfo();
            fileInfo.setFileName(file.getName());
            fileInfo.setFileOriginalName(file.getOriginalFilename());
            //文件大小, 字节数 转成KB需/1024
            fileInfo.setFileSize(file.getSize());
            fileInfo.setFileUrl(HuaWeiOBSUtil.uploadFile(file));
            fileInfo.setCreateDate(LocalDateTime.now());
            fileInfo.setContentType(file.getContentType());
            fileInfo.setStatus(FileConstants.FileStatus.NOMAL);
            list.add(fileInfo);
        }
        return list;
    }

}
